package cn.iocoder.yudao.module.engine.model.context;

import cn.iocoder.yudao.module.engine.model.aichat.AIChatQueue;
import cn.iocoder.yudao.module.engine.model.config.EngineConfig;
import cn.iocoder.yudao.module.engine.service.core.queue.audio.AudioQueue;
import cn.iocoder.yudao.module.engine.service.core.queue.llm.LLMMessageQueue;
import cn.iocoder.yudao.module.resource.api.model.AudioToneDTO;
import cn.iocoder.yudao.module.resource.api.model.CosplayDTO;
import io.netty.util.Timeout;
import lombok.Data;
import org.apache.commons.collections4.queue.CircularFifoQueue;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.concurrent.Semaphore;

@Data
public class EngineSessionContext {
    private final String wsSessionId;
    private final String gameMatchId;
    private final Long userId;
    private final CosplayDTO role;
    private final AudioToneDTO tone;
    private final Integer storyId;

    // 基于优先级的发送队列
    private final AudioQueue audioQueue;
    private final EngineConfig engineConfig;

    // 已经使用过的音频Id
    private final Collection<String> usedAudioIds = Collections.synchronizedCollection(new CircularFifoQueue<String>(100) {
        @Override
        public boolean add(String e) {
            if (!contains(e)) {
                return super.add(e);
            }
            return false;
        }
    });

    // AI聊天队列
    private final AIChatQueue aiChatQueue = new AIChatQueue();

    // 单用户并发限制
    private final Semaphore llmSemaphore;
    private final Semaphore ttsSemaphore;

    // 历史消息
    private final Integer historyMessageMaxSize;
    private final LLMMessageQueue historyMessageQueue;

    // 提醒定时任务
    private final Collection<Timeout> remindTimeoutList = Collections.synchronizedList(new ArrayList<>());

    // 计费
    private final BillingContext billingContext = new BillingContext();

    // 用户偏好
    private UserPreferenceContext userPreferenceCtx;

    public EngineSessionContext(String wsSessionId, String gameMatchId, Long userId,
                                CosplayDTO role, AudioToneDTO tone,
                                Integer storyId, Integer historyMessageMaxSize,
                                AudioQueue audioQueue, EngineConfig engineConfig) {
        this.wsSessionId = wsSessionId;
        this.gameMatchId = gameMatchId;
        this.userId = userId;
        this.role = role;
        this.tone = tone;
        this.storyId = storyId;
        this.historyMessageMaxSize = historyMessageMaxSize;
        this.historyMessageQueue = new LLMMessageQueue(historyMessageMaxSize);
        this.audioQueue = audioQueue;
        this.engineConfig = engineConfig;

        llmSemaphore = new Semaphore(engineConfig.getThreadPool().getLlmSemaphoreSize());
        ttsSemaphore = new Semaphore(engineConfig.getThreadPool().getTtsSemaphoreSize());
    }

    public Integer getRoleId() {
        return role.getId();
    }

    public Integer getToneId() {
        return tone.getId();
    }

    public void addUsedAudioId(String audioId) {
        usedAudioIds.add(audioId);
    }

    public void addUsedAudioIds(Collection<String> audioIds) {
        usedAudioIds.addAll(audioIds);
    }

    public void removeUsedAudioIds(Collection<String> audioIds) {
        usedAudioIds.removeAll(audioIds);
    }

    public void addRemindTimeout(Timeout timeout) {
        synchronized (remindTimeoutList) {
            remindTimeoutList.add(timeout);
        }
    }

    public void removeRemindTimeout(Timeout timeout) {
        synchronized (remindTimeoutList) {
            remindTimeoutList.remove(timeout);
        }
    }

    public void clearRemindTimeout() {
        synchronized (remindTimeoutList) {
            remindTimeoutList.clear();
        }
    }

    public int getAudioQueueSize() {
        return audioQueue.getDataList().size();
    }

}
